package com.caishi.lkx.exam.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.caishi.lkx.common.util.IndexUtil;
import com.caishi.lkx.exam.mapper.ExamCalendarMapper;
import com.caishi.lkx.exam.model.*;
import com.caishi.lkx.exam.service.*;
import com.caishi.lkx.exam.vo.IndexExamCalendarVo;
import com.zzw.common.entity.IBaseMapper;
import com.zzw.common.entity.impl.BaseEntity;
import com.zzw.common.entity.impl.BaseIntEntity;
import com.zzw.common.threadpool.SysThreadPool;

import com.caishi.lkx.exam.ienum.type.ColumnType;
import com.caishi.lkx.exam.ienum.type.PaperType;

import com.caishi.lkx.exam.model.re.ExColumnConfigReModel;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

/**
 * @author by liyihua
 * @date : 2022-01-06 14:29
 */
@Service("examCalendarService")
@Slf4j
public class ExamCalendarServiceImpl implements IExamCalendarService {
    @Resource
    private ExamCalendarMapper mapper;

    @Resource
    private ICategoryService categoryService;

    @Resource
    private IColumnService columnService;

    @Resource
    private IExColumnConfigReService columnConfigReService;

    @Resource
    private IChapterService chapterService;

    @Resource
    private IPaperService paperService;

    @Resource
    private IExamQuestionRankService examQuestionRankService;

    @Resource
    private IExamService examService;

    @Resource
    private IExamCalendarService examCalendarService;

    @Override
    public IBaseMapper<ExamCalendarModel, String> getMapper() {
        return mapper;
    }

    @Override
    public ExamCalendarModel getExamLately(String examId) {
        return selectFirst(wrappers()
                .eq(ExamCalendarModel::getExamId, examId)
                .ge(ExamCalendarModel::getExamDate, LocalDate.now())
                .orderByAsc(ExamCalendarModel::getExamDate)
        );
    }

    @SneakyThrows
    @Override
    public IndexExamCalendarVo tansClientVo(ExamCalendarModel model, boolean async) {
        var vo = new IndexExamCalendarVo();
        BeanUtil.copyProperties(model, vo);
        //考试时间不存在
        if (null == vo.getExamDate()) {
            vo.setExamDate(null);
        }
        if (vo.getCategoryId() != null && StrUtil.isEmpty(model.getCategoryName())) {
            vo.setCategoryName(categoryService.queryName(vo.getCategoryId()));
        }
        if (StrUtil.isEmpty(vo.getExamName())) vo.setExamName(examService.getById(vo.getExamId()).getName());
        var categoryIds = categoryService.selectList(categoryService.wrappers()
                .select(CategoryModel::getId)
                .eq(CategoryModel::getExamId, vo.getExamId())
        ).stream().map(BaseIntEntity::getId).toList();
        var columns = categoryIds.parallelStream()
                .map(v -> columnService.queryCategoryColumns(v))
                .flatMap(List::stream)
                .toList();
        if (CollUtil.isEmpty(columns)) return vo;
        Callable<List<IndexExamCalendarVo.QCount>> fr = () -> {
            List<IndexExamCalendarVo.QCount> qCounts = new LinkedList<>();
            var ids = columns.stream()
                    .filter(v -> v.getType() == ColumnType.chapterPractice)
                    .map(BaseEntity::getId).toList();
            if (!ids.isEmpty()) {
                ids = columnConfigReService.selectList(columnConfigReService.wrappers()
                                .in(ExColumnConfigReModel::getColumnId, ids))
                        .stream().map(ExColumnConfigReModel::getConfigId).toList();
                if (!ids.isEmpty()) {
                    var chapters = chapterService.selectList(chapterService.wrappers()
                            .select(ChapterModel::getPath, ChapterModel::getLeaf, BaseEntity::getId)
                            .in(BaseEntity::getId, ids));
                    ids = (async ? chapters.parallelStream() : chapters.stream()).map(m -> {
                        if (m.getLeaf()) {
                            return Collections.singletonList(m.getId());
                        }
                        return chapterService.allChildrenIds(m, -1, chapterService.wrappers().select(ChapterModel::getId).eq(ChapterModel::getLeaf, true));
                    }).flatMap(List::stream).distinct().toList();
                    var item = new IndexExamCalendarVo.QCount();
                    item.setCount(chapterService.selectSum(chapterService.wrappers().select(ChapterModel::getQcount).in(BaseEntity::getId, ids)).intValue());
                    if (item.getCount() > 0) {
                        item.setName(ColumnType.chapterPractice.getDesc());
                        item.setDesc("分知识点依次复习备考");
                        item.setCompany("题");
                        item.setColumnType(ColumnType.chapterPractice);
                        item.setSort(0);
                        qCounts.add(item);
                    }
                }
            }
            return qCounts;
        };
        var f = async ? SysThreadPool.submit(fr) : CompletableFuture.completedFuture(fr.call());
        List<IndexExamCalendarVo.QCount> qCounts = new LinkedList<>();
        var descMap = MapUtil.builder(PaperType.mock, "在线考试，测试复习水平")
                .put(PaperType.prophesy, "考前干货，预测命题方向")
                .put(PaperType.trueTopic, "历年真题，考前冲刺必备")
                .build();
        AtomicInteger index = new AtomicInteger(1);
        var columnIds = columnService.selectList(columnService.wrappers()
                .select(ColumnModel::getId)
                .in(ColumnModel::getCategoryId, categoryIds)
                .eq(ColumnModel::getType, ColumnType.paperLibrary)
        ).stream().map(BaseEntity::getId).toList();

        if (!columnIds.isEmpty()) {
            var paperConfig = columnConfigReService.selectList(columnConfigReService.wrappers()
                    .select(ExColumnConfigReModel::getConfigId)
                    .in(ExColumnConfigReModel::getColumnId, columnIds)
            );
            if (!paperConfig.isEmpty()) {
                var strem = Stream.of(PaperType.prophesy, PaperType.trueTopic, PaperType.mock);
                List<String> paperIds = paperConfig.stream().map(ExColumnConfigReModel::getConfigId).toList();
                List<List<String>> paperSplit = IndexUtil.splitList(paperIds);
                qCounts.addAll((async ? strem.parallel() : strem)
                        .map(type -> {
                            var item = new IndexExamCalendarVo.QCount();
                            int count = paperSplit.stream().mapToInt(ids -> paperService.selectCount(paperService.wrappers()
                                    .in(PaperModel::getId, ids)
                                    .eq(PaperModel::getPaperType, type)).intValue()).sum();
                            item.setCount(count);
                            if (item.getCount() > 0) {
                                item.setName(type.getDesc());
                                item.setCompany("套");
                                item.setDesc(descMap.get(type));
                                item.setColumnType(ColumnType.paperLibrary);
                                return item;
                            }
                            return null;
                        })
                        .filter(Objects::nonNull)
                        .toList());
                qCounts.forEach(v -> v.setSort(index.getAndIncrement()));
            }
        }
        qCounts.addAll(f.get());
        int examAllQuestion = 0;
        if (qCounts.size() < 4 && columns.stream().anyMatch(v -> v.getType() == ColumnType.specialPractice)) {
            examAllQuestion = (async ? categoryIds.parallelStream() : categoryIds.stream()).mapToInt(categoryService::allQuestionCount).sum();
            var item = new IndexExamCalendarVo.QCount();
            item.setName(ColumnType.specialPractice.getDesc());
            item.setDesc("集中训练某章节或题型");
            item.setCompany("题");
            item.setColumnType(ColumnType.specialPractice);
            item.setCount(examAllQuestion);
            item.setSort(10);
            qCounts.add(item);
        }
        if (qCounts.size() < 4 && columns.stream().anyMatch(v -> v.getType() == ColumnType.randomFormPaper)) {
            var item = new IndexExamCalendarVo.QCount();
            item.setName(ColumnType.randomFormPaper.getDesc());
            item.setDesc("全真模板随机抽题测评");
            item.setCompany("题");
            item.setColumnType(ColumnType.specialPractice);
            item.setCount(examAllQuestion);
            item.setSort(11);
            qCounts.add(item);
        }
        if (qCounts.size() < 4) {
            var item = new IndexExamCalendarVo.QCount();
            item.setName("高频错题");
            item.setDesc("大家都踩坑了啥题");
            item.setCompany("题");
            item.setCount(examQuestionRankService.selectCount(
                    ExamQuestionRank.ExamQuestionRankBaseModel.builder()
                            .examId(model.getExamId())
                            .build(),
                    examQuestionRankService.wrappers()
                            .eq(ExamQuestionRank.ExamQuestionRankBaseModel::getExamId, model.getExamId())
                            .gt(ExamQuestionRank::getErrorCount, 0)
            ).intValue());
            item.setSort(12);
            qCounts.add(item);
        }
        if (qCounts.size() < 4) {
            var item = new IndexExamCalendarVo.QCount();
            item.setName("热门试题");
            item.setDesc("大家都在做的试题");
            item.setCompany("题");
            item.setCount(examQuestionRankService.selectCount(
                    ExamQuestionRank.ExamQuestionRankBaseModel.builder()
                            .examId(model.getExamId())
                            .build(),
                    examQuestionRankService.wrappers()
                            .eq(ExamQuestionRank.ExamQuestionRankBaseModel::getExamId, model.getExamId())
                            .gt(ExamQuestionRank::getDoCount, 0)
            ).intValue());
            item.setSort(13);
            qCounts.add(item);
        }
        if (qCounts.size() < 4) {
            var item = new IndexExamCalendarVo.QCount();
            item.setName("热门收藏");
            item.setDesc("大家都收藏了啥题");
            item.setCompany("题");
            item.setCount(examQuestionRankService.selectCount(
                    ExamQuestionRank.ExamQuestionRankBaseModel.builder()
                            .examId(model.getExamId())
                            .build(),
                    examQuestionRankService.wrappers()
                            .eq(ExamQuestionRank.ExamQuestionRankBaseModel::getExamId, model.getExamId())
                            .gt(ExamQuestionRank::getCollectCount, 0)
            ).intValue());
            item.setSort(14);
            qCounts.add(item);
        }
        qCounts.sort(Comparator.comparing(IndexExamCalendarVo.QCount::getSort));
        vo.setContent(qCounts);
        return vo;
    }
}
